Scapy:send函数剖析(参数、返回值、应用) 您所在的位置:网站首页 loop count Scapy:send函数剖析(参数、返回值、应用)

Scapy:send函数剖析(参数、返回值、应用)

2023-08-11 01:24| 来源: 网络整理| 查看: 265

        send函数是Scapy中发包的重要函数,使用Scapy的程序员免不了经常与它打交道。但是,我们真的了解它吗?思此有感,我特地翻阅了源码,并将自己的分析写成博客分享给大家。水平不高,如有疑惑请在评论区留言。

        文档中是这样介绍send函数的(怀疑机翻):

scapy.sendrecv.send(x, iface=None, **kargs)

在第三层发送数据包

参数

x -- 包裹

inter -- 两个数据包之间的时间(以秒为单位)(默认值为0)

loop -- send packet indefinitely (default 0) (bing翻译为“无限期发送数据包 默认值 0”)

count -- 要发送的数据包数(默认无=1)

verbose -- 详细模式(默认无=conf.详细) (指conf.verb)

realtime -- 在发送下一个包之前,请检查是否已发送了一个包

return_packets -- 返回发送的数据包

socket -- 要使用的套接字(默认为conf.L3socket(kargs))

iface -- 发送数据包的接口

monitor -- (不在linux上)以监视模式发送

返回: 没有 (可能指None)

(源码附后)

        绿色背景的是我的注释。

        不难看出,send函数的参数列表显式地由三个部分组成:x指要发送的包,iface指发送数据包的接口,还有一个接受不定参数的kargs。

文档中提到的参数和返回值,经研究后,结果如下:

参数解析:

x:

        类型为_PacketIterable,无默认值。

        指要发送的包,可传递包、迭代器或存有包的列表。不能传元组(原因不明)。send函数的底层使用for循环遍历x参数,按理来说可迭代对象均可传入。

 

inter:

        类型为int或float,默认为0。

        发包后的停顿时间,以秒为单位。注释上面标注为int型,实际传入float也可正常运行。这是因为它调用的是time模块中的sleep函数。

 

loop:

        类型为int,默认为0。

        发送数据包的数量,是发包while循环的条件。如果没有传递loop的值,同时也没有传递count的值,则loop值会被设为-1。如果传了count的值,则loop会被设为-count。每次循环后,loop值加1,加到0时循环停止。

 

count:

        类型为int,默认为None。

        发送包的数量。当count为None时,loop被设为-1,反之被设为-count。注意不要传入非None、int的值,否则报错。如果传入非负数,正常运行。传入小数,while循环因为loop始终不为0而不会停止。传入正数,因为send函数底层的做法是将loop赋为-count,在每次循环且loop小于0时执行loop += 1,所以loop始终不为0,故循环不会终止。

 

verbose:

        类型为int,默认值为conf.verb,即2。

        是否开启详细模式。该值为真时,打印发包过程的详细信息(其实也没多详细)。即每法送一个包,打印一个点,并在发包结束之后打印发送的总包数。

 

realtime:

        类型为bool,默认为False。

        是否在发送下一个包之前,检查是否已发送了一个包。

        这个参数有没有用我持怀疑态度。在捋完那段绕来绕去的源码后,我得出一个等式:

第一次发包时间-第一个包构造时的时间>第二次发包时间-第二个包构造时时间,只要满足这个不等式,send函数就会使用sleep函数阻塞进程第二个包构造时间-第一个包构造时间+第一次发包时间-第二次发包时间。这段代码是如何检查是否发送了一个包的,我不得而知。

 

return_packets:

        类型为bool,默认为False。

        是否返回发送的数据包。注意,返回的是一个PacketList对象,不是包。PacketList可以用访问下标的方法访问其中的元素。具体的包储存在res成员中。

 

socket:

        类型为SuperSocket, 默认值为conf.L3socket(kargs))。

        使用的套接字。当缺省时,send函数会自行处理。

 

iface:

        类型为str,默认值None。该参数用于指定网卡的名称,网卡的使用由send函数内部完成。如传入"eth0",send函数就会使用eth0网卡发包。当缺省时,send函数会自行选择合适的网卡。

 

montor:

        (用的Linux,没找到这个东西)

返回值解析:

        文档中提到的返回值为None。但经源码分析之后,send函数的返回值应有两个:None或PacketList。当return_packets参数为真时,返回PacketList类,反之返回None。

        None值不多做解释。

        PacketList是定义在plist模块中的一个类。它的一个父类_PacketList重写了__repr__(str类进行类型转换和print函数调用的方法)、__iter__(迭代开始时调用的方法)、__getitem__(索引操作使用的方法)、__add__(重载加法运算符)、__len__(len函数调用的方法)。由此可看出Scapy中对运算符、语句和内置函数的运用不少。

        故此可实现以下操作:

        1.使用print函数打印或调用str类转换send函数的返回值。

        output:

                

        2.像迭代range函数的返回值一样迭代send函数的返回值。

        3.使用索引调取储存在send函数返回值的数据包。这并不是对其中res成员的简单访问,它还涉及其他返回值,目前还没有研究。

        4.使用加法运算符在send函数的返回值之间运算。使用这个东西需要注意。如下:

        代码:

                a = b = send(IP(), return_packets=True)

                d = a + b

                print(d)

        output:

                . (这里有个点)

                Sent 1 packets.

                

        如标红部分所示,多少个PacketList类相加,这里的算式就有多少个元素。故此,如果真的要将send函数的返回值相加,谨慎打印。

        5.使用len函数计算send函数返回值中的数据包数量。

        此外,使用PackekList的summary方法,可以按行打印其中储存的包的summary方法结果,即按行打印各个包的梗概。

        当然,返回的PacketList有点鸡肋,毕竟那是我自己发出去的包。但是,在发送随机包的时候,的确可能需要返回发送的包。

        据此,可以总结一些send函数的用法:

1.将count参数设为负值,由此死循环发送数据包,之后用Ctrl+C停止程序

from scapy.all import IP, TCP, send packet = IP() / TCP() send(packet, count=-1)

output:

┌──(matriller㉿Hack)-[~/桌面/Practice] └─$ sudo python demo.py ..................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................^C Sent 850 packets.

        因为send函数中使用专门的变量来储存发包数,加上整个发包过程处于try-exept语句中,当按下Ctrl+C时,send函数捕获KeyboardInterrupt错误,之后根据传参决定是否展示信息,及传回None或PacketList对象。

        这可以用于事先不知道要发送多少个包的情况。尽管使用while循环可以获得同样的效果,但是调用send函数的花销很大,每次循环都调用一次send函数,那么程序性能会明显下降。

2.传入inter参数,使每次发包之后停顿一段时间

from scapy.all import IP, TCP, send from time import time, sleep packet = IP() / TCP() t = time() send(packet, count=5, inter=0.5) print(time()-t) t = time() for i in range(5): send(packet) sleep(0.5) print(time()-t)

output:

┌──(matriller㉿Hack)-[~/桌面/Practice] └─$ sudo python demo.py ..... Sent 5 packets. 2.5401618480682373 . Sent 1 packets. . Sent 1 packets. . Sent 1 packets. . Sent 1 packets. . Sent 1 packets. 2.712531805038452

        这个方法很重要。调用send函数的花销很大,将停顿的工作交由send函数底层去实现可以提高程序性能。在上方的输出中,仅仅只是发送5个包,使用for循环停顿的比起传参停顿的已经有明显的迟钝。而在网络编程中,要发送的绝不仅5个包。

3.向verbose传入假值关闭send函数自身的输出

from scapy.all import IP, TCP, send from time import time, sleep packet = IP() / TCP() send(packet, verbose=0)

output:

┌──(matriller㉿Hack)-[~/桌面/Practice] └─$ sudo python demo.py

        没有了每发一个包都要打印的点和结束时的总数。有时我们在使用Scapy时不希望send函数打印消息到屏幕,那么这个参数会大有用处。

        由于send函数底层将verbose参数作为if语句的条件,向verbose传入下列值都可以得到相同的效果:(None不行)

0,0.0,'',b'',False,[],()

4.向x参数传入列表,提升发包速度

from scapy.all import IP, TCP, send from time import time, sleep packet = [IP() / TCP() for i in range(5)] print(len(packet)) print(type(packet)) print(packet) t = time() send(packet) print(time()-t) t = time() for i in range(5): send(IP() / TCP()) print(time()-t)

output:

┌──(matriller㉿Hack)-[~/桌面/Practice] └─$ sudo python demo.py 5 [, , , , ] ..... Sent 5 packets. 0.03799152374267578 . Sent 1 packets. . Sent 1 packets. . Sent 1 packets. . Sent 1 packets. . Sent 1 packets. 0.1679677963256836

        可以看到,向send函数传入列表以使其一次性发送,性能比使用for循环多次调用send函数性能要高的多。详情可以看我的另一篇文章:

Scapy:快速syn洪水攻击(syn flood)_Matriller的博客-CSDN博客利用scapy的特性提升进行syn洪水攻击(syn floor)的速度favicon32.icohttps://blog.csdn.net/m0_71713477/article/details/128556822?spm=1001.2014.3001.5501

源码部分:

def __gen_send(s, # type: SuperSocket x, # type: _PacketIterable inter=0, # type: int loop=0, # type: int count=None, # type: Optional[int] verbose=None, # type: Optional[int] realtime=False, # type: bool return_packets=False, # type: bool *args, # type: Any **kargs # type: Any ): # type: (...) -> Optional[PacketList] """ An internal function used by send/sendp to actually send the packets, implement the send logic... It will take care of iterating through the different packets """ if isinstance(x, str): x = conf.raw_layer(load=x) if not isinstance(x, Gen): x = SetGen(x) if verbose is None: verbose = conf.verb n = 0 if count is not None: loop = -count elif not loop: loop = -1 sent_packets = PacketList() if return_packets else None p = None try: while loop: dt0 = None for p in x: if realtime: ct = time.time() if dt0: st = dt0 + float(p.time) - ct if st > 0: time.sleep(st) else: dt0 = ct - float(p.time) s.send(p) if sent_packets is not None: sent_packets.append(p) n += 1 if verbose: os.write(1, b".") time.sleep(inter) if loop < 0: loop += 1 except KeyboardInterrupt: pass finally: try: cast(Packet, x).sent_time = cast(Packet, p).sent_time except AttributeError: pass if verbose: print("\nSent %i packets." % n) return sent_packets def _send(x, # type: _PacketIterable _func, # type: Callable[[NetworkInterface], Type[SuperSocket]] inter=0, # type: int loop=0, # type: int iface=None, # type: Optional[_GlobInterfaceType] count=None, # type: Optional[int] verbose=None, # type: Optional[int] realtime=False, # type: bool return_packets=False, # type: bool socket=None, # type: Optional[SuperSocket] **kargs # type: Any ): # type: (...) -> Optional[PacketList] """Internal function used by send and sendp""" need_closing = socket is None iface = resolve_iface(iface or conf.iface) socket = socket or _func(iface)(iface=iface, **kargs) results = __gen_send(socket, x, inter=inter, loop=loop, count=count, verbose=verbose, realtime=realtime, return_packets=return_packets) if need_closing: socket.close() return results @conf.commands.register def send(x, # type: _PacketIterable iface=None, # type: Optional[_GlobInterfaceType] **kargs # type: Any ): # type: (...) -> Optional[PacketList] """ Send packets at layer 3 :param x: the packets :param inter: time (in s) between two packets (default 0) :param loop: send packet indefinitely (default 0) :param count: number of packets to send (default None=1) :param verbose: verbose mode (default None=conf.verb) :param realtime: check that a packet was sent before sending the next one :param return_packets: return the sent packets :param socket: the socket to use (default is conf.L3socket(kargs)) :param iface: the interface to send the packets on :param monitor: (not on linux) send in monitor mode :returns: None """ iface = _interface_selection(iface, x) return _send( x, lambda iface: iface.l3socket(), iface=iface, **kargs )

参考文献:

浅析Python运算符重载_viclee108的博客-CSDN博客_python 运算符重载scapy.sendrecv — Scapy 2.4.4. 文档

https://github.com/secdev/scapy/blob/master/scapy/sendrecv.py#L413-L44

 

 

 

 



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有